#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "image_container_smart.h"

#include <Ecore.h>
#include <Evas.h>

#include <stdio.h>
#include <stdlib.h>

#define E_SMART_OBJ_GET(smart, o) \
  { \
     if (!o) return; \
     smart = evas_object_smart_data_get(o); \
     if (!smart) return; \
  }

#define E_SMART_OBJ_GET_RETURN(smart, o, ret) \
  { \
     if (!o) return ret; \
     smart = evas_object_smart_data_get(o); \
     if (!smart) return ret; \
  }

typedef struct _Image_Container_Smart_Data Image_Container_Smart_Data;

struct _Image_Container_Smart_Data
{
   Evas_Object *clipper;
   Evas_List *items;
   int scroll_offset;
   Evas_Bool preview_mode;
};

static void _image_container_smart_add(Evas_Object * obj);
static void _image_container_smart_del(Evas_Object * obj);
static void _image_container_smart_move(Evas_Object * obj, Evas_Coord x, Evas_Coord y);
static void _image_container_smart_resize(Evas_Object * obj, Evas_Coord w, Evas_Coord h);
static void _image_container_smart_show(Evas_Object * obj);
static void _image_container_smart_hide(Evas_Object * obj);
static void _image_container_smart_color_set(Evas_Object * obj, int r, int g, int b, int a);
static void _image_container_smart_clip_set(Evas_Object * obj, Evas_Object * clip);
static void _image_container_smart_clip_unset(Evas_Object * obj);

static void _image_container_smart_fix(Evas_Object * obj);

static Evas_Smart *_image_container_smart = NULL;

EAPI Evas_Object *
image_container_object_add(Evas *evas)
{
   if (!_image_container_smart)
     {
	static const Evas_Smart_Class sc =
	  {
	     "image_container_object",
	       EVAS_SMART_CLASS_VERSION,
	       _image_container_smart_add,
	       _image_container_smart_del,
	       _image_container_smart_move,
	       _image_container_smart_resize,
	       _image_container_smart_show,
	       _image_container_smart_hide,
	       _image_container_smart_color_set,
	       _image_container_smart_clip_set,
	       _image_container_smart_clip_unset,
	       NULL
	  };
        _image_container_smart = evas_smart_class_new(&sc);
     }
   return evas_object_smart_add(evas, _image_container_smart);
}

EAPI Evas_Object *
image_container_object_append(Evas_Object *obj, const char *file, const char *key)
{
   Image_Container_Smart_Data *imsd;
   Evas_Object *child;

   E_SMART_OBJ_GET_RETURN(imsd, obj, NULL);
   child = evas_object_image_add(evas_object_evas_get(obj));
   evas_object_image_file_set(child, file, key);
   evas_object_smart_member_add(child, obj);
   evas_object_repeat_events_set(child, 1);
   evas_object_clip_set(child, imsd->clipper);
   evas_object_show(child);
   imsd->items = evas_list_append(imsd->items, child);
   _image_container_smart_fix(obj);
   return child;
}

EAPI Evas_Object *
image_container_object_prepend(Evas_Object *obj, const char *file, const char *key)
{
   Image_Container_Smart_Data *imsd;
   Evas_Object *child;

   E_SMART_OBJ_GET_RETURN(imsd, obj, NULL);
   child = evas_object_image_add(evas_object_evas_get(obj));
   evas_object_image_file_set(child, file, key);
   evas_object_smart_member_add(child, obj);
   evas_object_repeat_events_set(child, 1);
   evas_object_clip_set(child, imsd->clipper);
   evas_object_show(child);
   imsd->items = evas_list_prepend(imsd->items, child);
   _image_container_smart_fix(obj);
   return child;
}

EAPI void
image_container_object_remove(Evas_Object *obj, Evas_Object *item)
{
   Image_Container_Smart_Data *imsd;
   Evas_List *l;
   Evas_Object *child;

   E_SMART_OBJ_GET(imsd, obj);
   for (l = imsd->items; l; l = l->next)
     {
	child = l->data;
	if (item == child)
	  {
	     evas_object_del(child);
	     evas_list_remove_list(imsd->items, l);
	     break;
	  }
     }
}

EAPI void
image_container_object_remove_all(Evas_Object *obj)
{
   Image_Container_Smart_Data *imsd;
   Evas_List *l;
   Evas_Object *child;

   E_SMART_OBJ_GET(imsd, obj);
   for (l = imsd->items; l; l = l->next)
     {
	child = l->data;
	evas_object_del(child);
     }
   imsd->items = evas_list_free(imsd->items);
}

EAPI Evas_List *
image_container_object_items_get(Evas_Object *obj)
{
   Image_Container_Smart_Data *imsd;
   Evas_List *items;
   Evas_List *l;

   E_SMART_OBJ_GET_RETURN(imsd, obj, NULL);
   items = NULL;
   for (l = imsd->items; l; l = l->next)
     items = evas_list_append(items, l->data);
   return items;
}

EAPI int
image_container_object_items_count(Evas_Object *obj)
{
   Image_Container_Smart_Data *imsd;

   E_SMART_OBJ_GET_RETURN(imsd, obj, 0);
   return evas_list_count(imsd->items);
}

EAPI void
image_container_object_scroll_offset_set(Evas_Object *obj, int val)
{
   Image_Container_Smart_Data *imsd;

   E_SMART_OBJ_GET(imsd, obj);
   if (imsd->scroll_offset == val) return;
   imsd->scroll_offset = val;
   _image_container_smart_fix(obj);
}

EAPI int
image_container_object_scroll_offset_get(Evas_Object *obj)
{
   Image_Container_Smart_Data *imsd;

   E_SMART_OBJ_GET_RETURN(imsd, obj, 0);
   return imsd->scroll_offset;
}

EAPI void
image_container_object_preview_mode_set(Evas_Object *obj, Evas_Bool preview_mode)
{
   Image_Container_Smart_Data *imsd;

   E_SMART_OBJ_GET(imsd, obj);
   if (imsd->preview_mode == preview_mode) return;
   imsd->preview_mode = preview_mode;
   _image_container_smart_fix(obj);
}

EAPI Evas_Bool
image_container_object_preview_mode_get(Evas_Object *obj)
{
   Image_Container_Smart_Data *imsd;

   E_SMART_OBJ_GET_RETURN(imsd, obj, 0);
   return imsd->preview_mode;
}

EAPI void
image_container_object_items_bounds_get(Evas_Object *obj, int *x, int *y, int *w, int *h)
{
   Image_Container_Smart_Data *imsd;
   Evas_Object *first_item;
   Evas_Object *last_item;

   E_SMART_OBJ_GET(imsd, obj);
   if (!x && !y && !w && !h) return;
   if (!imsd->items)
     {
	if (x) *x = 0;
	if (y) *y = 0;
	if (w) *w = 0;
	if (h) *h = 0;
	return;
     }

   first_item = imsd->items->data;
   last_item = evas_list_last(imsd->items)->data;
   if (first_item == last_item)
     evas_object_geometry_get(imsd->clipper, x, y, w, h);
   else
     {
	int fix = 0, fiy = 0;

	evas_object_geometry_get(first_item, &fix, &fiy, NULL, NULL);
	if (x) *x = fix;
	if (y) *y = fiy;

	if (w || h)
	  {
	     int lix = 0, liy, liw = 0, lih = 0;

	     evas_object_geometry_get(last_item, &lix, &liy, &liw, &lih);
	     if (w) *w = lix + liw - fix;
	     if (h) *h = liy + lih - fiy;
	  }
     }
}

/* Private routines */
static void
_image_container_smart_add(Evas_Object * obj)
{
   Image_Container_Smart_Data *imsd;

   imsd = calloc(1, sizeof(Image_Container_Smart_Data));
   if (!imsd) return;

   imsd->clipper = evas_object_rectangle_add(evas_object_evas_get(obj));
   evas_object_smart_member_add(imsd->clipper, obj);
   evas_object_repeat_events_set(imsd->clipper, 1);
   evas_object_color_set(imsd->clipper, 255, 255, 255, 255);

   evas_object_smart_data_set(obj, imsd);
}

static void
_image_container_smart_del(Evas_Object * obj)
{
   Image_Container_Smart_Data *imsd;

   E_SMART_OBJ_GET(imsd, obj);
   image_container_object_remove_all(obj);
   evas_object_del(imsd->clipper);
}

static void
_image_container_smart_move(Evas_Object * obj, Evas_Coord x, Evas_Coord y)
{
   Image_Container_Smart_Data *imsd;

   E_SMART_OBJ_GET(imsd, obj);
   evas_object_move(imsd->clipper, x, y);
   _image_container_smart_fix(obj);
}

static void
_image_container_smart_resize(Evas_Object * obj, Evas_Coord w, Evas_Coord h)
{
   Image_Container_Smart_Data *imsd;

   E_SMART_OBJ_GET(imsd, obj);
   evas_object_resize(imsd->clipper, w, h);
   _image_container_smart_fix(obj);
}

static void
_image_container_smart_show(Evas_Object * obj)
{
   Image_Container_Smart_Data *imsd;

   E_SMART_OBJ_GET(imsd, obj);
   evas_object_show(imsd->clipper);
}

static void
_image_container_smart_hide(Evas_Object * obj)
{
   Image_Container_Smart_Data *imsd;

   E_SMART_OBJ_GET(imsd, obj);
   evas_object_hide(imsd->clipper);
}

static void
_image_container_smart_color_set(Evas_Object * obj, int r, int g, int b, int a)
{
   Image_Container_Smart_Data *imsd;

   E_SMART_OBJ_GET(imsd, obj);
   evas_object_color_set(imsd->clipper, r, g, b, a);
}

static void
_image_container_smart_clip_set(Evas_Object * obj, Evas_Object * clip)
{
   Image_Container_Smart_Data *imsd;

   E_SMART_OBJ_GET(imsd, obj);
   evas_object_clip_set(imsd->clipper, clip);
}

static void
_image_container_smart_clip_unset(Evas_Object * obj)
{
   Image_Container_Smart_Data *imsd;

   E_SMART_OBJ_GET(imsd, obj);
   evas_object_clip_unset(imsd->clipper);
}

static void
_image_container_smart_fix(Evas_Object * obj)
{
   Image_Container_Smart_Data *imsd;
   Evas_Coord x, y, w, h;
   int iw, ih;
   Evas_List *l;
   Evas_Object *child;

   E_SMART_OBJ_GET(imsd, obj);
   evas_object_geometry_get(imsd->clipper, &x, &y, &w, &h);
   x += imsd->scroll_offset;
   if (imsd->preview_mode && imsd->items)
     w /= evas_list_count(imsd->items);
   for (l = imsd->items; l; l = l->next)
     {
	child = l->data;
	evas_object_image_size_get(child, &iw, &ih);
	if (!imsd->preview_mode)
	  w = ih ? (iw * h / ih) : 0;
	else
	  h = iw ? (ih * w / iw) : 0;
	evas_object_move(child, x, y);
	evas_object_resize(child, w, h);
	evas_object_image_fill_set(child, 0, 0, w, h);
	x += w;
     }
}
